package github.ziwukun.jsonql.utils;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import cn.hutool.core.util.ObjectUtil;
import github.ziwukun.jsonql.lang.Select;
import github.ziwukun.jsonql.lang.SelectBuilder;
import github.ziwukun.jsonql.orm.CtnProp;
import github.ziwukun.jsonql.orm.FmProp;
import github.ziwukun.jsonql.orm.JoinProp;
import github.ziwukun.jsonql.orm.JoinPropCtn;
import github.ziwukun.jsonql.orm.Model;
import github.ziwukun.jsonql.orm.Prop;
import github.ziwukun.jsonql.orm.RltProp;

public class ModelUtils {
	private static Map<Model, Select> MODEL_SELECTS = new ConcurrentHashMap<>();
	/**
	 * 获取模型的所有选项
	 * @return
	 */
	public static Select getModelCompletedSelect(Model model) {
		if(MODEL_SELECTS.containsKey(model)) {
			return MODEL_SELECTS.get(model);
		}
		SelectBuilder builder = Select.builder();
		addModelSelect(model,builder);
		Select result = builder.build();
		
		MODEL_SELECTS.put(model, result);
		return result;
	}
	
	private static void addModelSelect(Model model,SelectBuilder builder) {
		List<Prop> props = model.listProps();
		for (Prop prop : props) {
			// 直接属性
			if(prop instanceof CtnProp || prop instanceof JoinProp) {
				builder.props(prop.propName());
			}
			else if(prop instanceof FmProp) {
				FmProp fmProp = (FmProp)prop;
				builder.prop(prop.propName(), s -> {
					addModelSelect(fmProp.propModel(), s);
				});
			}
			else if(prop instanceof RltProp) {
				RltProp rltProp = (RltProp)prop;
				builder.prop(rltProp.propName(), s -> {
					addModelSelect(rltProp.propModel(),s);
				});
			}
		}
	}
	
	private static Map<Model,Map<JoinPropCtn,List<JoinProp>>> JOIN_CTN_2_JOIN_PROPS = new ConcurrentHashMap<>();
	/**
	 * 反转链接属性和链接表的对应关系
	 * @param model
	 * @return
	 */
	public static Map<JoinPropCtn,List<JoinProp>> mapJoinProps(Model model){
		// 没有链接属性
		if(model.isJoinPropEmpty()) {
			return new HashMap<>();
		}
		// 从缓存获取
		if(JOIN_CTN_2_JOIN_PROPS.containsKey(model)) {
			return ObjectUtil.cloneByStream(JOIN_CTN_2_JOIN_PROPS.get(model));
		}
		
		Map<JoinPropCtn,List<JoinProp>> result = new HashMap<JoinPropCtn, List<JoinProp>>();
		for (JoinProp joinProp : model.listJoinProps()) {
			if(!result.containsKey(joinProp.ofCtn())) {
				List<JoinProp> joinProps = new LinkedList<>();
				result.put(joinProp.ofCtn(), joinProps);
			}
			result.get(joinProp.ofCtn()).add(joinProp);
		}
		JOIN_CTN_2_JOIN_PROPS.put(model, result);
		
		// 复制拷贝 防止外部修改
		return ObjectUtil.cloneByStream(result);
	}
}
